<?php
// +----------------------------------------------------------------------
// | 萤火商城系统 [ 致力于通过产品和服务，帮助商家高效化开拓市场 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2017~2023 https://www.yiovo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed 这不是一个自由软件，不允许对程序代码以任何形式任何目的的再发行
// +----------------------------------------------------------------------
// | Author: 萤火科技 <admin@yiovo.com>
// +----------------------------------------------------------------------
declare (strict_types=1);

namespace app\api\model;

use app\api\model\{Goods as GoodsModel, OrderRefund as OrderRefundModel, Setting as SettingModel};
use app\api\service\{User as UserService, Payment as PaymentService};
use app\api\service\order\{PaySuccess as OrderPaySuccesService, source\Factory as OrderSourceFactory};
use app\common\model\Order as OrderModel;
use app\common\service\{Order as OrderService, order\Complete as OrderCompleteService, order\Refund as RefundService};
use app\common\enum\{order\refund\AuditStatus as AuditStatusEnum,
    order\refund\RefundStatus as RefundStatusEnum,
    Setting as SettingEnum,
    OrderType as OrderTypeEnum,
    order\PayType as OrderPayTypeEnum,
    order\PayStatus as PayStatusEnum,
    order\OrderStatus as OrderStatusEnum,
    order\ReceiptStatus as ReceiptStatusEnum,
    order\DeliveryStatus as DeliveryStatusEnum
};
use app\common\library\helper;
use cores\exception\BaseException;

/**
 * 订单模型
 * Class Order
 * @package app\api\model
 */
class Order extends OrderModel
{
    /**
     * 隐藏字段
     * @var array
     */
    protected $hidden = [
        'store_id',
        'update_time'
    ];

    // 信息提示
    private $message = '';

    /**
     * 待支付订单详情
     * @param string $orderNo 订单号
     * @return null|static
     */
    public static function getPayDetail(string $orderNo): ?Order
    {
        return self::detail(['order_no' => $orderNo, 'pay_status' => PayStatusEnum::PENDING, 'is_delete' => 0], ['goods' => ['goods'], 'user']);
    }

    /**
     * 订单支付事件
     * @param int $payType
     * @return bool
     */
    public function onPay(int $payType = OrderPayTypeEnum::WECHAT): bool
    {
        // 判断订单状态
        $orderSource = OrderSourceFactory::getFactory($this['order_source']);
        if (!$orderSource->checkOrderStatusOnPay($this)) {
            $this->error = $orderSource->getError();
            return false;
        }
        // 余额支付
        if ($payType == OrderPayTypeEnum::BALANCE) {
            return $this->onPaymentByBalance($this['order_no']);
        }
        return true;
    }

    /**
     * 构建支付请求的参数
     * @param self $order 订单信息
     * @param int $payType 订单支付方式
     * @return array
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public function onOrderPayment(self $order, int $payType): array
    {
        if ($payType == OrderPayTypeEnum::WECHAT) {
            return $this->onPaymentByWechat($order);
        }
        return [];
    }

    /**
     * 构建微信支付请求
     * @param self $order 订单详情
     * @return array
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    protected function onPaymentByWechat(self $order): array
    {
        return PaymentService::wechat(
            $order['order_id'],
            $order['order_no'],
            $order['pay_price'],
            OrderTypeEnum::ORDER
        );
    }

    /**
     * 立即购买：获取订单商品列表
     * @param int $goodsId 商品ID
     * @param string $goodsSkuId 商品SKU
     * @param int $goodsNum 购买数量
     * @return mixed
     * @throws BaseException
     */
    public function getOrderGoodsListByNow(int $goodsId, string $goodsSkuId, int $goodsNum)
    {
        // 获取商品列表
        $model     = new GoodsModel;
        $goodsList = $model->isGoodsGradeMoney(false)->getListByIdsFromApi([$goodsId]);
        if ($goodsList->isEmpty()) {
            throwError('未找到商品信息');
        }
        // 隐藏冗余的属性
        $goodsList->hidden(GoodsModel::getHidden(['content', 'goods_images', 'images']));
        foreach ($goodsList as &$item) {
            // 商品sku信息
            $goodsInfo['skuInfo'] = GoodsModel::getSkuInfo($item, $goodsSkuId, false);
            // 商品封面 (优先sku封面)
            $item['goods_image'] = $item['skuInfo']['goods_image'] ?: $item['goods_image'];
            // 商品单价
            $item['goods_price'] = $item['skuInfo']['goods_price'];
            // 商品购买数量
            $item['total_num'] = $goodsNum;
            // 商品SKU索引
            $item['goods_sku_id'] = $item['skuInfo']['goods_sku_id'];
            // 商品购买总金额
            $item['total_price'] = helper::bcmul($item['goods_price'], $goodsNum);
        }
        return $goodsList;
    }

    /**
     * 余额支付标记订单已支付
     * @param string $orderNo 订单号
     * @return bool
     */
    public function onPaymentByBalance(string $orderNo): bool
    {
        // 获取订单详情
        $service = new OrderPaySuccesService($orderNo);
        // 发起余额支付
        $status = $service->onPaySuccess(OrderPayTypeEnum::BALANCE);
        if (!$status) {
            $this->error = $service->getError();
        }
        return $status;
    }

    /**
     * 获取用户订单列表
     * @param string $type 订单类型 (all全部 payment待付款 received待发货 deliver待收货 comment待评价)
     * @return \think\Paginator
     * @throws \think\db\exception\DbException
     * @throws BaseException
     */
    public function getList(string $type = 'all'): \think\Paginator
    {
        // 筛选条件
        $filter = [];
        // 订单数据类型
        switch ($type) {
            case 'all':
                break;
            case 'payment':
                $filter['pay_status']   = PayStatusEnum::PENDING;
                $filter['order_status'] = OrderStatusEnum::NORMAL;
                break;
            case 'delivery':
                $filter['pay_status']      = PayStatusEnum::SUCCESS;
                $filter['delivery_status'] = DeliveryStatusEnum::NOT_DELIVERED;
                $filter['order_status']    = OrderStatusEnum::NORMAL;
                break;
            case 'received':
                $filter['pay_status']      = PayStatusEnum::SUCCESS;
                $filter['delivery_status'] = DeliveryStatusEnum::DELIVERED;
                $filter['receipt_status']  = ReceiptStatusEnum::NOT_RECEIVED;
                $filter['order_status']    = OrderStatusEnum::NORMAL;
                break;
            case 'comment':
                $filter['is_comment']   = 0;
                $filter['order_status'] = OrderStatusEnum::COMPLETED;
                break;
        }
        // 当前用户ID
        $userId = UserService::getCurrentLoginUserId();

        return $this->with(['goods.image', 'ordersub'])
            ->alias('order')
            ->field('order.*')
            ->leftjoin('order_sub', 'order_sub.order_id = order.order_id')
            ->where($filter)
            ->where(function ($query) use ($type) {
                if ($type == 'all') {
                    $orwhere = [['order.order_parent_id', '>', '0'], ['order.pay_status', '=', '10']];
                    $query->whereOr($orwhere);
                } elseif ($type == 'payment') {
                    $query->where('order.order_parent_id', '=', 0);
                } else {
                    $query->where('order.order_parent_id', '>', 0);
                }
                // 可以继续添加其他条件
            })
            ->where('order.user_id', '=', $userId)
            ->where('order.is_delete', '=', 0)
            ->order(['order.create_time' => 'desc'])
            ->paginate(15);
    }

    public function getAllList($orderList)
    {
        // 当前用户ID
        $userId = UserService::getCurrentLoginUserId();
        if ($orderList['data']) {
            $order_ids        = array_column($orderList['data'], 'order_id');
            $OrderRefundModel = new OrderRefundModel();
            $refundOrder      = $OrderRefundModel->where('order_id', 'in', $order_ids)
                ->where('user_id', '=', $userId)
                ->where('status', '=', RefundStatusEnum::COMPLETED)
                ->where('type', '=', 10)
                ->select()->toArray();
            $refundOrderList  = [];
            if ($refundOrder) {
                foreach ($refundOrder as $value) {
                    $refundOrderList[$value['order_id']][] = $value['order_goods_id'];
                }
            } else {
                return $orderList;
            }
            foreach ($orderList['data'] as $key => $v) {
                if ($refundOrderList && isset($refundOrderList[$v['order_id']])) {
                    $order_status = false;
                    foreach ($v['goods'] as $good_k => $good_v) {
                        if (!in_array($good_v['order_goods_id'], $refundOrderList[$v['order_id']])) {
                            $order_status = true;
                        }
                    }
                    if ($order_status == false) {
                        $orderList['data'][$key]['order_status'] = 50;//订单全部退款
                    }
                }

            }
        }
        return $orderList;
    }

    /**
     * 取消订单
     * @return bool|mixed
     */
    public function cancel()
    {
        if ($this['delivery_status'] == DeliveryStatusEnum::DELIVERED) {
            $this->error = '已发货订单不可取消';
            return false;
        }
        // 订单是否已支付
        $isPay = $this['pay_status'] == PayStatusEnum::SUCCESS;
        // 提示信息
        $this->message = $isPay ? '订单已申请取消，需等待后台审核' : '订单已取消成功';
        // 订单取消事件
        return $this->transaction(function () use ($isPay) {
            // 订单取消事件
            $isPay == false && OrderService::cancelEvent($this);
            // 更新订单状态: 已付款的订单设置为"待取消", 等待后台审核
            return $this->save(['order_status' => $isPay ? OrderStatusEnum::APPLY_CANCEL : OrderStatusEnum::CANCELLED]);
        });
    }

    /**
     * 确认收货
     * @return bool|mixed
     */
    public function receipt()
    {
        // 验证订单是否合法
        // 条件1: 订单必须已发货
        // 条件2: 订单必须未收货
        if ($this['delivery_status'] != 20 || $this['receipt_status'] != 10) {
            $this->error = '该订单不合法';
            return false;
        }
        return $this->transaction(function () {
            // 更新订单状态
            $status = $this->save([
                'receipt_status' => 20,
                'receipt_time'   => time(),
                'order_status'   => 30
            ]);
            // 执行订单完成后的操作
            $OrderCompleteService = new OrderCompleteService();
            $OrderCompleteService->complete([$this], static::$storeId);
            return $status;
        });
    }

    /**
     * 获取当前用户订单数量
     * @param string $type 订单类型 (all全部 payment待付款 received待发货 deliver待收货 comment待评价)
     * @return int
     * @throws BaseException
     */
    public function getCount(string $type = 'all'): int
    {
        // 筛选条件
        $filter = [];
        // 订单数据类型
        switch ($type) {
            case 'all':
                break;
            case 'payment':
                $filter['pay_status'] = PayStatusEnum::PENDING;
                break;
            case 'received':
                $filter['pay_status']      = PayStatusEnum::SUCCESS;
                $filter['delivery_status'] = DeliveryStatusEnum::DELIVERED;
                $filter['receipt_status']  = ReceiptStatusEnum::NOT_RECEIVED;
                break;
            case 'delivery':
                $filter['pay_status']      = PayStatusEnum::SUCCESS;
                $filter['delivery_status'] = DeliveryStatusEnum::NOT_DELIVERED;
                $filter['order_status']    = OrderStatusEnum::NORMAL;
                break;
            case 'comment':
                $filter['is_comment']   = 0;
                $filter['order_status'] = OrderStatusEnum::COMPLETED;
                break;
        }
        // 当前用户ID
        $userId = UserService::getCurrentLoginUserId();
        // 查询数据
        if ($type == 'payment') {
            return $this->where('user_id', '=', $userId)
                ->where('order_parent_id', '=', 0)
                ->where('order_status', '<>', 20)
                ->where($filter)
                ->where('is_delete', '=', 0)
                ->count();
        } else {
            return $this->where('user_id', '=', $userId)
                ->where('order_status', '<>', 20)
                ->where('order_parent_id', '>', 0)
                ->where($filter)
                ->where('is_delete', '=', 0)
                ->count();
        }

    }

    /**
     * 获取用户订单详情(含关联数据)
     * @param int $orderId 订单ID
     * @return Order|array|null
     * @throws BaseException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    public static function getUserOrderDetail(int $orderId)
    {
        // 关联查询
        $with = [
            'goods' => ['image', 'goods', 'refund'],
            'orderaddress', 'address', 'express'
        ];
        // 查询订单记录
        $order = static::getDetail($orderId, $with);
        /* $parent_order = static::getDetail($order['order_parent_id'], ['ordersub']);
         $order['ordersub'] = $parent_order['ordersub'];*/
        // 该订单是否允许申请售后
        $order['isAllowRefund'] = static::isAllowRefund($order);
        $order['good_type']     = '';
        $order['address']       = $order['address'] ? $order['address'] : $order['orderaddress'];
        //商品退款用户不能评价
        if (isset($order['goods'])) {
            foreach ($order['goods'] as $key => $value) {
                if (!empty($value['goods']) && $value['goods']['good_type'] == 'virtual_good') {
                    $order['good_type']        = 'virtual_good';
                    $order['recharge_account'] = $order['goods'][0]['recharge_account'];
                    $order['goods_no']         = $order['goods'][0]['goods_no'];//心链虚拟商品编号
                }

                if (isset($value['refund']['apply_desc']) && $value['refund']['type'] == 30) {
                    $order['goods'][$key]['apply_desc'] = $value['refund']['apply_desc'];
                }
            }
            /*$status = false;
            foreach ($order['goods'] as $key => $value) {
                if (empty($value['refund']) || (isset($value['refund']['type']) && $value['refund']['type'] != 10)) {
                    $status = true;
                }
            }*/
            /*if ($status == false) {
                $order['order_status'] = 50;//商品全部退款，用户不能评价
            }*/
        }
        return $order;
    }

    /**
     * 获取用户订单详情(仅订单记录)
     * @param int $orderId
     * @param array $with
     * @return Order|array|null
     * @throws BaseException
     */
    public static function getDetail(int $orderId, array $with = [])
    {
        // 查询订单记录
        $order = static::detail([
            'order_id' => $orderId,
            'user_id'  => UserService::getCurrentLoginUserId(),
        ], $with);
        empty($order) && throwError('订单不存在');
        return $order;
    }

    /**
     * 获取当前用户待处理的订单数量
     * @return array
     * @throws BaseException
     */
    public function getTodoCounts(): array
    {
        return [
            'payment'  => $this->getCount('payment'),    // 待付款的订单
            'delivery' => $this->getCount('delivery'),  // 待发货的订单
            'received' => $this->getCount('received'),  // 待收货的订单
            'refund'   => OrderRefundModel::getCountByUnderway(),  // 进行中的售后单
        ];
    }

    // 返回提示信息
    public function getMessage(): string
    {
        return $this->message;
    }

    /**
     * 当前订单是否允许申请售后
     * @param Order $order
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\DbException
     * @throws \think\db\exception\ModelNotFoundException
     */
    private static function isAllowRefund(self $order): bool
    {
        // 必须是已发货的订单
        if ($order['delivery_status'] != DeliveryStatusEnum::DELIVERED) {
            return false;
        }
        // 允许申请售后期限(天)
        $refundDays = SettingModel::getItem(SettingEnum::TRADE)['order']['refund_days'];
        // 不允许售后
        if ($refundDays == 0) {
            return false;
        }
        // 当前时间超出允许申请售后期限
        if (
            $order['receipt_status'] == ReceiptStatusEnum::RECEIVED
            && time() > ($order->getData('receipt_time') + ((int)$refundDays * 86400))
        ) {
            return false;
        }
        return true;
    }

    /**
     * 订单直接退款
     * @param $order_id
     * @return false|mixed
     */
    /*public function OrderRefundByOrderId($order_id,$apply_desc='')
    {
        //获取订单下商品信息
        $data = static::detail($order_id, ['goods']);
        if (empty($data)) {
            return false;
        }
        $data['bd_type']         = 0;
        $data['pay_cash']        = 0.00;
        $data['deduction_value'] = 0.00;
        $data['refund_goods']           = [];
        if ($data['goods']) {
            foreach ($data['goods'] as $key => $good_info) {
                if ($good_info['bd_type'] != 0) {
                    $data['bd_type'] = $good_info['bd_type'];
                }
                $data['pay_cash']        = helper::bcadd($data['pay_cash'], $good_info['pay_cash']);
                $data['deduction_value'] = helper::bcadd($data['deduction_value'], $good_info['deduction_value']);
                $item['order_goods_id']  = $good_info['order_goods_id'];
                $item['refund_money'] = $good_info['total_pay_price'];
                $item['order_id'] = $good_info['order_id'];
                $item['user_id'] = $good_info['user_id'];
                $item['type'] = 10;//退货退款
                $item['apply_desc'] = $apply_desc;
                $item['audit_status'] = AuditStatusEnum::REVIEWED;//同意退款
                $item['is_receipt'] = 1;
                $item['status'] = RefundStatusEnum::COMPLETED;
                $item['store_id'] = self::$storeId;
                $data['refund_goods'][] = $item;
            }
        }
        if(empty($data['refund_goods'])){
            return false;
        }
        return $this->transaction(function () use ($data) {
            $OrderRefundModel = new OrderRefundModel();
            $OrderRefundModel->saveAll($data['refund_goods']);//添加售后订单
            // 执行退款操作
            (new RefundService)->execute($data);
        });
    }*/

    /**
     * 直接订单取消并退款，无需审核
     * @param $order_id
     * @return false|mixed
     */
    public function OrderCancelByOrderId($order_id)
    {
        //获取订单下商品信息
        $result = static::detail($order_id, ['goods']);
        // 判断订单是否有效
        if ($result['pay_status'] != PayStatusEnum::SUCCESS) {
            $this->error = '该订单不合法';
            return false;
        }
        // 订单取消事件
        return $this->transaction(function () use ($result) {
            $cancelData                    = $result;
            $cancelData['bd_type']         = 0;
            $cancelData['pay_cash']        = 0.00;
            $cancelData['deduction_value'] = 0.00;
            if ($result['goods']) {
                foreach ($result['goods'] as $good_info) {
                    if ($good_info['bd_type'] != 0) {
                        $cancelData['bd_type'] = $good_info['bd_type'];
                    }
                    $cancelData['pay_cash']        = helper::bcadd($cancelData['pay_cash'], $good_info['pay_cash']);
                    $cancelData['deduction_value'] = helper::bcadd($cancelData['deduction_value'], $good_info['deduction_value']);
                }
            }
            // 执行退款操作
            (new RefundService)->execute($cancelData);
            // 订单取消事件
            OrderService::cancelEvent($cancelData);
            self::update(['order_status' => OrderStatusEnum::CANCELLED, 'delivery_status' => DeliveryStatusEnum::NOT_DELIVERED, 'receipt_status' => ReceiptStatusEnum::NOT_RECEIVED], ['order_id' => $result['order_id']]);
        });
    }
}
